/*
	 在代码1基础上加入平台总线+设备数
	 
/ {
	...
	
	//add pwr
	pwr_button {
		compatible = "rk3399,power-button";
		gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
		interrupt-parent = <&gpio0>;//对应的上级中断控制器是 gpio0
		interrupts = <5 IRQ_TYPE_EDGE_BOTH>; //中断号 触发方式 GPIO0 A5
	};
	...
};



*/


#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/of.h> // of				
#include <linux/of_gpio.h> //gpio	
#include <linux/gpio.h>	
#include <dt-bindings/gpio/gpio.h>
#include <linux/interrupt.h>
#include <linux/input.h>


//1.声明输入设备对象
static struct input_dev *button_dev;

static int gpio_button;
static int irqno;

//定义中断处理函数
static irqreturn_t button_handler(int irqno, void *dev)
{
	
	int value;
	value = gpio_get_value(gpio_button);
	if (value) 
		input_report_key(button_dev, KEY_A, 0); //0--松开
	else
		input_report_key(button_dev, KEY_A, 1); //1--按下
	input_sync(button_dev); //同步事件 上报结束

	
	printk("<kernel>call %s()\n", __func__); 
	return IRQ_HANDLED;
}


//当平台驱动和平台设备匹配时调用probe函数
static int button_probe(struct platform_device *pdev)
{
	int ret;
	
	//获得匹配的device_node对象, 然后拿设备节点下硬件数据
	struct device_node *button_ctrl_node = pdev->dev.of_node;


	//2.创建输入设备对象
	button_dev = input_allocate_device();
	if (!button_dev) {
		printk("input_allocate_device fail\n");
		return  -ENOMEM;
	}

	//3.初始化输入设备对象
//	set_bit(EV_KEY, button_dev->evbit); //为输入设备对象设置事件类型
//	set_bit(KEY_A, button_dev->keybit); //为输入设备对象设置键码
	
	button_dev->evbit[0] = BIT_MASK(EV_KEY);																					
	button_dev->keybit[BIT_WORD(KEY_A)] = BIT_MASK(KEY_A);

	//设置输入设备对象的信息
	button_dev->name = "xyd power key button";
	button_dev->phys = "rk3399 powwer key";
	button_dev->id.vendor = 0x11;
	button_dev->id.product = 0x22;
	button_dev->id.version = 48;
	
	//4.注册输入设备对象
	ret = input_register_device(button_dev);
	if (ret) {
		printk("input_register_device fail \n");
		ret = -EBUSY;
		goto err_input_register_device;

	}

	//5.硬件初始化
	gpio_button = of_get_named_gpio(button_ctrl_node, "gpios", 0);
	if (gpio_is_valid(gpio_button)) {
		printk("gpio_button=%d\n", gpio_button);
	} else {
		printk("of_get_named_gpio_flags fail\n");
		ret =-EINVAL;
		goto err_request_irq;
	}
	//获取中断号
	irqno = gpio_to_irq(gpio_button);
	printk("irqno=%d\n", irqno);

	ret = request_irq(irqno, button_handler, IRQ_TYPE_EDGE_BOTH, "pwr_key_Int", NULL);
	if (ret) {
		printk("request_irq fail\n");
		ret= -EFAULT;
	}

	printk("<kernel> call %s()\n", __func__);  
	return 0;

	

err_request_irq:
	input_unregister_device(button_dev);
err_input_register_device:
	input_free_device(button_dev);
	return ret;
		

	
}

//当平台驱动和平台设备分离时调用remove函数
static int button_remove(struct platform_device *pdev)
{
	free_irq(irqno, NULL);
	input_unregister_device(button_dev);
	input_free_device(button_dev);
	printk("<kernel> call %s()\n", __func__);  
	return 0;

}

static const struct platform_device_id button_id_table[] = {
	{
		.name = "rk3399_button",
		.driver_data = 0x1,
	}, {
		.name = "rk3288_button",
		.driver_data = 0x2,
	}, {
		.name = "rk3568_button",
		.driver_data = 0x3,
	}, {
		/* id table */
	}
};

static const struct of_device_id button_of_match[] = {
	{ .compatible = "rk3399,power-button", },  //必须和设备树节点的compatible属性匹配
	{ /*of match table*/ }
};


//定义平台驱动对象并初始化
static struct platform_driver rk_button_driver = {
	.probe		= button_probe,
	.remove		= button_remove,
	.driver		= {
		.name	= "rk_button", //平台驱动的字符串名称
		.of_match_table = button_of_match, //指向匹配设备树节点的数组
	},
	.id_table = button_id_table, //指向匹配平台设备的数组
};



static int __init driver_mod_init(void)
{
	printk("<kernel> call %s()\n", __func__);  
	return platform_driver_register(&rk_button_driver);
}


static void __exit driver_mod_exit(void)
{
	printk("<kernel> call %s() @ %d\n", __FUNCTION__, __LINE__);  
	platform_driver_unregister(&rk_button_driver);
}


module_init(driver_mod_init); 
module_exit(driver_mod_exit); 
MODULE_LICENSE("GPL"); 



